//
// Created by QU on 24-6-24.
//
#include <iostream>
#include <functional>
#include <utility>
#include <memory>
#include <vector>
#include <map>
#include <set>
#include <new>
#include <thread>
#include <algorithm>
#include <array>
#include <string>
#include <deque>

using std::cout, std::cin, std::endl;

/*
在C++中有一种典型的错误叫作“Static Initialization OrderFiasco”，指的是因为静态初始化顺序错误导致的问题。因为这种错
误往往发生在main函数之前，所以比较难以排查。举一个典型的例子，假设有两个静态对象x和y分别存在于两个不同的源文件中。其中
一个对象x的构造函数依赖于对象y。没错，就是这样，现在我们有50%的可能性会出错，
**因为我们没有办法控制哪个对象先构造。如果对象x在y之前构造，那么就会引发一个未定义的结果。**
为了避免这种问题的发生，我们通常希望使用常量初始化程序去初始化静态变量。
不幸的是，常量初始化的规则很复杂，需要一种方法帮助我们完成检查工作，当不符合常量初始化程序的时候可以在编译阶段报错。
于是在C++20标准中引入了新的constinit说明符。
*/

// 正如上文所描述的constinit说明符主要用于具有静态存储持续时间的变量声明上，它要求变量具有常量初始化程序。
constinit constexpr int x = 11;

int main(int argc, const char* argv[])
{
    // constinit 在 C++20 中引入，主要用于确保具有静态存储持续时间的变量在编译时完成初始化。它的使用场景主要包括以下几个方面：

    // 1. 防止静态初始化顺序问题
    // 在 C++ 中，静态变量的初始化顺序不确定，尤其是当它们分布在不同的翻译单元（编译单元）时。使用 constinit 可以确保变量在编译时初始化，避免初始化顺序问题。例如：

    constinit int a = 42;

    struct S {
        static constinit int b;
    };

    constinit int S::b = a + 1;  // 确保在编译时初始化
    // 2. 确保线程安全
    // 对于静态存储持续时间的变量，编译时初始化是线程安全的。使用 constinit 可以避免在运行时初始化时可能出现的竞争条件（race condition）。例如：

    constinit int sharedValue = 100;

    void someFunction() {
        // 在多线程环境下访问 sharedValue 是安全的
        int localValue = sharedValue;
    }
    // 3. 提高性能
    // 由于 constinit 保证了变量在编译时初始化，避免了运行时的初始化开销，从而提高了程序的启动速度和整体性能。例如：

    constinit std::array<int, 5> arr = {1, 2, 3, 4, 5};

    // arr 在编译时已经初始化完毕，运行时无需再进行初始化

    // 4. 使用 constexpr 函数进行初始化
    // 当使用 constexpr 函数进行初始化时，可以结合 constinit 确保这些初始化在编译时完成。例如：

    constexpr int computeValue(int x) {
        return x * x;
    }

    constinit int result = computeValue(5);  // 编译时初始化

    // 5. 防止意外的非静态初始化
    // 在一些情况下，可能会意外地使用非静态初始化。使用 constinit 可以强制编译器检查并防止这种情况发生。例如：

    int runtimeValue() {
        return 42;
    }

    // constinit int a = runtimeValue();  // 编译错误，runtimeValue 不是 constexpr 函数
    // 总结来说，constinit 在确保静态存储持续时间的变量在编译时初始化方面提供了重要的保证，避免了初始化顺序问题，提高了线程安全性和性能，并有助于编译时检查初始化是否符合要求。这些特性使其在需要高性能和高可靠性的系统编程中特别有用。
    return 0;
}
